package com.everflourish.yeah100.utils.markingsystem;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 解析答题卡56*13的工具类
 *
 * @author datian
 */
public class Parse56x16Util {
    /**
     * 学生的id，即学号 键 格式：字符串
     * 例：student_id=**56*5*4[56]*
     * *：表示学号列没有填涂
     * [56]:表示学号列填涂了两项
     **/
    public static final String STUDENT_ID = "student_id";
    /**
     * 科目的键 格式：List集合
     * 例：courses=[英语]
     **/
    public static final String COURSES = "courses";
    /**
     * 试卷类型的键 格式：字符串
     * 例子： type=B
     **/
    public static final String TYPE = "type";
    // 科目
    private static final String[][] COURSE = {{"15", "语文"}, {"17", "数学"},
            {"19", "英语"}, {"21", "物理"}, {"23", "化学"}, {"25", "政治"},
            {"27", "历史"}, {"29", "地理"}, {"31", "生物"}, {"33", "理综"},
            {"35", "文综"}, {"37", "计算器"}, {"39", "其他"}};

    // 行的数量
    private static final int TOTAL_ROW_COUNT = 56;
    // 列的数量,前原本13列，为了凑齐两个byte，在前面默认加上3列
    private static final int TOTAL_RANK_COUNT = 16;

    /**
     * 1..... 将byte数组中的数转为二进制
     *
     * @param byteList 存放在list中的字节集合
     * @return 转换后的二进制数集合
     */
    public static Map<String, Object> byteToMap(List<Byte> byteList) {
        int[] arrUnsignedInt = null;
        // 存放填涂的二维字节数组， 1为未填涂，0为填涂，转为字节1对应49,0对应48
        byte[][] binaryBytes = new byte[TOTAL_ROW_COUNT][TOTAL_RANK_COUNT];
        StringBuffer sbuf = new StringBuffer();
        arrUnsignedInt = new int[byteList.size()];
        for (int i = 0, j = 0; i < byteList.size(); i++) {
            arrUnsignedInt[j++] = byteList.get(i) & 0xFF;// 转成无符号的整形
        }

        for (int i = 0; i < arrUnsignedInt.length; i++) {
            String binaryString = Integer.toBinaryString(arrUnsignedInt[i]);
            int length = binaryString.length();
            if (length < 8) {
                for (int j = 0; j < 8 - length; j++) {
                    binaryString = "0" + binaryString;
                }
            }
            sbuf.append(binaryString);
        }
        String binaryStr = sbuf.toString();

        for (int i = 0, j = 0; i < binaryStr.length(); i += 16) {
            byte[] bytes = binaryStr.substring(i, i + 16).getBytes();
            binaryBytes[j++] = bytes;
        }

        return binaryBytesToMap(binaryBytes);
    }

    private static Map<String, Object> binaryBytesToMap(byte[][] binaryBytes) {
        Map<String, Object> map = new HashMap<String, Object>();

        String sNumber = "";
        // 判断学号是那个数字？【0--9】
        String numberFlag = "";
        // 一列中的涂的号码个数，（ 学号一列中，只能涂一个地方）。
        int numberCount = 0;
        // -----------------------------判断学号----------------------------------------
        for (int j = 3; j < 13; j++) {// 列，从4列到13列，下标从0开始，所以3即对应第4列
            for (int i = 0, k = 0; i < 10; i++, k++) { // 行，从第1行到10行。下标从0开始，所以0即对应第1行
                byte isOne = binaryBytes[i][j]; // 二维数组，第一个代表行，第二个代表列
                if (isOne == 48) { // 48代表为填涂，对应int类型0
                    numberFlag += k + "";
                    numberCount++;
                }
            }
            if (numberCount == 1) {// 判断涂了多个数字，如果不是一个，直接报错
                sNumber += numberFlag;
                numberFlag = "";
            } else if (numberCount > 1) {
                numberFlag = "[" + numberFlag + "]";
                sNumber += numberFlag;
            } else if (numberCount == 0) {
                sNumber += "*";
            }
            numberCount = 0;
            numberFlag = "";
        }
        //处理学号  如  **123*23*** 处理后变成123*23
        while (true) {
            if (sNumber.startsWith("*")) {
                sNumber = sNumber.substring("*".length());
            }
            if (sNumber.endsWith("*")) {
                sNumber = sNumber.substring(0, sNumber.length() - "*".length());
            }
            if (!sNumber.startsWith("*") && !sNumber.endsWith("*")) {
                break;
            }
        }
        map.put(STUDENT_ID, sNumber);

        // -----------------------------判断学科----------------------------------------
        List<String> singleAnswerList = new ArrayList<String>();

        // 判断学科
        for (int i = 15, k = 0; i < 40; i += 2, k++) { // 行，从第16行到41行。下标从0开始，所以15即对应第16行
            int isOne = binaryBytes[i][3]; // 二维数组，第一个代表行，第二个代表列3表示第4列
            if (isOne == 48) {
                String tempCourse = COURSE[k][1];
                singleAnswerList.add(tempCourse);
            }
        }
        map.put(COURSES, singleAnswerList);
        singleAnswerList = new ArrayList<String>();

        // -----------------------------判断试卷类型A卷 B卷----------------------------------------
        //判断试卷类型
        String type = "";
        if (binaryBytes[11][3] == 48) {
            type += "A";
        }
        if (binaryBytes[12][3] == 48) {
            type += "B";
        }
        map.put(TYPE, type);
        // -----------------------------判断答案1到90----------------------------------------
        String tempFlag = "";
        int tCount = 0;
        // 判断答案(1到45题)
        for (int j = 11; j < 56; j++) { // 行，从第12行(下标对应为11)开始，到第56列（下标对应为55）
            for (int i = 6, k = 0; i < 10; i++, k++) {// 列，从第7列（下标对应为6）开始，到第10列（下标对应为9）
                // ，k只是一个标记，0对应A,1对应B，2对应C,3对应D
                byte isOne = binaryBytes[j][i];
                if (isOne == 48) {
                    switch (k) {
                        case 0:
                            tempFlag = "A";
                            break;
                        case 1:
                            tempFlag = "B";
                            break;
                        case 2:
                            tempFlag = "C";
                            break;
                        case 3:
                            tempFlag = "D";
                            break;
                    }
                    singleAnswerList.add(tempFlag); // 将一道题的答案存放到一个list集合中，因为题型包含多项选择题
                    tempFlag = "";
                }
            }
            map.put(++tCount + "", singleAnswerList);
            singleAnswerList = new ArrayList<String>();
        }

        // 判断答案(46到90题)
        for (int j = 11; j < 56; j++) { // 行，从第12行(下标对应为11)开始，到第56列（下标对应为55）
            for (int i = 12, k = 0; i < 16; i++, k++) {// 列，从第13列（下标对应为12）开始，到第16列（下标对应为15）
                // ，k只是一个标记，0对应A,1对应B，2对应C,3对应D
                byte isOne = binaryBytes[j][i];
                if (isOne == 48) {
                    switch (k) {
                        case 0:
                            tempFlag = "A";
                            break;
                        case 1:
                            tempFlag = "B";
                            break;
                        case 2:
                            tempFlag = "C";
                            break;
                        case 3:
                            tempFlag = "D";
                            break;
                    }
                    singleAnswerList.add(tempFlag); // 将一道题的答案存放到一个list集合中，因为题型包含多项选择题
                    tempFlag = "";
                }
            }
            map.put(++tCount + "", singleAnswerList);
            singleAnswerList = new ArrayList<String>();
        }

        return map;
    }

}
